package cn.chen.server.listener;

import java.util.concurrent.TimeUnit;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import cn.chen.server.adapter.ServerChannelHandlerAdapter;
import cn.chen.server.config.NettyServerConfig;
import cn.chen.server.util.ObjectCodec;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * Netty服务器监听器
 *
 * @author wangchen
 */
@Component
public class NettyServerListener {
	private static final Logger LOGGER = LoggerFactory.getLogger(NettyServerListener.class);

	/**
	 * 创建bootstrap
	 */
	private ServerBootstrap serverBootstrap = new ServerBootstrap();
	/**
	 * BOSS
	 */
	private EventLoopGroup boss = new NioEventLoopGroup();
	/**
	 * Worker
	 */
	private EventLoopGroup work = new NioEventLoopGroup();
	/**
	 * 通道适配器
	 */
	@Resource
	private ServerChannelHandlerAdapter channelHandlerAdapter;
	/**
	 * NETT服务器配置类
	 */
	@Resource
	private NettyServerConfig nettyConfig;

	/**
	 * 关闭服务器方法
	 */
	@PreDestroy
	public void close() {
		LOGGER.info("关闭服务器....");
		// 优雅退出
		boss.shutdownGracefully();
		work.shutdownGracefully();
	}

	/**
	 * 开启及服务线程
	 */
	public void start() {
		// 从配置文件中(application.yml)获取服务端监听端口号
		int port = nettyConfig.getPort();
		// 指定此套接口排队的最大连接个数
		serverBootstrap.group(boss, work).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)
				.handler(new LoggingHandler(LogLevel.INFO));
		try {
			// 设置事件处理
			serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel ch) {
					ChannelPipeline pipeline = ch.pipeline();
					// 添加心跳支持
					pipeline.addLast(new IdleStateHandler(60, 0, 0, TimeUnit.SECONDS));
					pipeline.addLast(channelHandlerAdapter);
					// 基于定长的方式解决粘包/拆包问题
					pipeline.addLast(new LengthFieldBasedFrameDecoder(nettyConfig.getMaxFrameLength(), 0, 2, 0, 2));
					pipeline.addLast(new LengthFieldPrepender(2));
					// 序列化
					pipeline.addLast(new ObjectCodec());

				}
			});
			LOGGER.info("netty服务器在[{}]端口启动监听", port);
			ChannelFuture f = serverBootstrap.bind("0.0.0.0", port).sync();
			f.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			LOGGER.info("[出现异常] 释放资源");
			boss.shutdownGracefully();
			work.shutdownGracefully();
		}
	}
}
